package com.hejia.alauda.service;

import static com.hejia.alauda.event.EventConstant.MONGODB_KEY_LOCK_ORDER_FAILED;
import static com.hejia.alauda.utils.DateTimeUtil.getMaxDate;
import static com.hejia.alauda.utils.RateUtil.calculateSettlementDate;
import static com.hejia.alauda.utils.Utils.formatDate;
import static com.hejia.alauda.utils.Utils.formatDateTime;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.commons.lang3.time.DateUtils.addDays;
import static org.springframework.util.CollectionUtils.isEmpty;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hejia.alauda.Constants;
import com.hejia.alauda.entity.Agreement;
import com.hejia.alauda.entity.BankCard;
import com.hejia.alauda.entity.BankCard.Status;
import com.hejia.alauda.entity.BankInfo;
import com.hejia.alauda.entity.BankMaintain;
import com.hejia.alauda.entity.BonusOrder;
import com.hejia.alauda.entity.Financing;
import com.hejia.alauda.entity.FinancingIncomeRule;
import com.hejia.alauda.entity.Message;
import com.hejia.alauda.entity.Order;
import com.hejia.alauda.entity.OrderBankCardChange;
import com.hejia.alauda.entity.Parameter;
import com.hejia.alauda.entity.PayGate;
import com.hejia.alauda.entity.PayGateBank;
import com.hejia.alauda.entity.PayNotifyLog;
import com.hejia.alauda.entity.PayOrder;
import com.hejia.alauda.entity.Product;
import com.hejia.alauda.entity.ProductEarningsRule;
import com.hejia.alauda.entity.Protocol;
import com.hejia.alauda.entity.Redpacket;
import com.hejia.alauda.entity.RepaymentOrder;
import com.hejia.alauda.entity.User;
import com.hejia.alauda.entity.example.BankCardExample;
import com.hejia.alauda.entity.example.BankInfoExample;
import com.hejia.alauda.entity.example.BankMaintainExample;
import com.hejia.alauda.entity.example.BonusOrderExample;
import com.hejia.alauda.entity.example.OrderExample;
import com.hejia.alauda.entity.example.PayGateBankExample;
import com.hejia.alauda.entity.example.PayGateExample;
import com.hejia.alauda.entity.example.RepaymentOrderExample;
import com.hejia.alauda.event.EventConstant;
import com.hejia.alauda.event.MessageEvent;
import com.hejia.alauda.exception.BusinessException;
import com.hejia.alauda.persistence.mongodb.PayNotifyLogRepository;
import com.hejia.alauda.persistence.mybatis.BalanceMapper;
import com.hejia.alauda.persistence.mybatis.BankCardMapper;
import com.hejia.alauda.persistence.mybatis.BankInfoMapper;
import com.hejia.alauda.persistence.mybatis.BankMaintainMapper;
import com.hejia.alauda.persistence.mybatis.BonusOrderMapper;
import com.hejia.alauda.persistence.mybatis.FinancingIncomeRuleMapper;
import com.hejia.alauda.persistence.mybatis.FinancingMapper;
import com.hejia.alauda.persistence.mybatis.InterestMapper;
import com.hejia.alauda.persistence.mybatis.OrderBankCardChangeMapper;
import com.hejia.alauda.persistence.mybatis.OrderMapper;
import com.hejia.alauda.persistence.mybatis.PayGateBankMapper;
import com.hejia.alauda.persistence.mybatis.PayGateMapper;
import com.hejia.alauda.persistence.mybatis.PayOrderMapper;
import com.hejia.alauda.persistence.mybatis.ProductMapper;
import com.hejia.alauda.persistence.mybatis.RepaymentOrderMapper;
import com.hejia.alauda.persistence.mybatis.UserMapper;
import com.hejia.alauda.utils.DateTimeUtil;
import com.hejia.alauda.utils.LLPayUtil;
import com.hejia.alauda.utils.Pager;
import com.hejia.hermes.entity.SMS;
import com.hejia.hermes.service.SMSService;
import com.jytpay.config.JytPayConfig;
import com.jytpay.util.JytPayClient;
import com.yeepay.yjpay.YeepayApiConfig;
import com.yeepay.yjpay.entity.BindCard;
import com.yeepay.yjpay.entity.UserBindCard;
import com.yeepay.yjpay.service.PayAPIService;
/**
 * Created by Johnny(johnny@hejiajinrong.com) on 15/3/3.
 */

@Service
public class PaymentServiceImpl implements PaymentService {

	protected final Log logger = LogFactory.getLog(getClass());

	@Resource
	private PayGateBankMapper payGateBankMapper;

	@Resource
	private PayGateMapper payGateMapper;

	@Resource
	private PayNotifyLogRepository pnl;

	@Resource
	private BankCardMapper bankCardMapper;

	@Resource
	private BankInfoMapper bankInfoMapper;

	@Resource
	private OrderMapper orderMapper;

	@Resource
	private ProductMapper productMapper;

	@Resource
	private FinancingMapper financingMapper;

	@Resource
	private InterestMapper interestMapper;

	@SuppressWarnings("rawtypes")
	@Resource
	private RedisTemplate redisTemplate;

	@Resource
	private BalanceAndFinancingService balanceAndFinancingService;

	@Resource
	private CreditService creditService;

	@Resource
	private UserMapper userMapper;

	@Resource
	private BalanceMapper balanceMapper;

	@Resource
	private UserService userService;

	@Resource
	private OrderService orderService;

	@Resource
	private BankMaintainMapper bankMaintainMapper;

	@Resource 
	private RepaymentOrderMapper repaymentOrderMapper;
	
	@Resource
	private OrderBankCardChangeMapper orderBankCardChangeMapper;
	
	@Resource
	private CommonService commonService;
	
	@Resource
	private FinancingIncomeRuleMapper financingIncomeRuleMapper;
	
	@Resource(name = "sendSMS")
	private SMSService smsService;
	
	@Resource
	private RedEnvelopeService redEnvelopeService;
	
	@Resource 
	private BonusOrderMapper bonusOrderMapper;
	
	@Resource
	private PayOrderMapper payOrderMapper;
	
	@Resource
	private MessageService messageService;
	
	@Resource
	private JytPayConfig jytPayConfig;

	@Resource
	private ConfigureService configureService;
	
	@Resource
	private ProductService productService;
	
	@Resource(name="executor")
	private AsyncTaskExecutor executor;
	
	@Resource
	private FinancingService financingService;
	
	private static Map<String,String[]> BANK_BIN_MAP;
	
	@Override
	public boolean addPayGateBank(PayGateBank payGateBank) {
		return payGateBankMapper.insert(payGateBank) > 0;
	}

	@Override
	public boolean deletePayGateBank(PayGateBank payGateBank) {
		return payGateBankMapper.deleteByPrimaryKey(payGateBank) > 0;
	}

	@Override
	public PayGateBank findPayGateBankById(Long id) {
		return payGateBankMapper.selectByPrimaryKey(id);
	}

	@Override
	public boolean modifyPayGateBank(PayGateBank payGateBank) {
		return payGateBankMapper.updateByPrimaryKey(payGateBank) > 0;
	}

	@Override
	public List<PayGateBank> getPayGateBankByPayGateId(Long payGateId) {
		PayGateBankExample exp = new PayGateBankExample();
		exp.appendCriterion("paygateid =", payGateId);
		return payGateBankMapper.selectByExample(exp, null);
	}

	@Override
	public boolean deletePayGateBankByPid(Long id) {
		return payGateBankMapper.deletePayGateBankByPid(id);
	}

	@Override
	public PayGateBank getPayGateBankByPayGateIdAndBankcode(Long payGateId,
			String bankcode) {
		PayGateBankExample exp = new PayGateBankExample();
		exp.appendCriterion("paygateid =", payGateId);
		exp.appendCriterion("bankcode =", bankcode);
		return payGateBankMapper.selectOneByExample(exp);

	}

	@Override
	public Pager<PayGate> findAllPayGate(Pager<PayGate> pager) {
		return findAllPayGate(pager, new PayGateExample());
	}

	@Override
	public Pager<PayGate> findAllPayGate(Pager<PayGate> pager,
			PayGateExample example) {
		example.setOrderByClause("priority asc");
		pager.setList(payGateMapper.selectByExample(example, pager));
		pager.setTotalCount(payGateMapper.countByExample(example));
		return pager;
	}

	@Override
	public boolean savePayGate(PayGate payGate) {
		return payGateMapper.insert(payGate) > 0;
	}

	@Override
	public PayGate getPayGateById(Long id) {
		return payGateMapper.selectByPrimaryKey(id);
	}

	@Override
	public boolean modifyPayGate(PayGate payGate) {
		return payGateMapper.updateByPrimaryKey(payGate) > 0;
	}

	@Override
	public boolean deletePayGate(Long id) {
		PayGate payGate = payGateMapper.selectByPrimaryKey(id);
		return payGateMapper.deleteByPrimaryKey(payGate) > 0;
	}
	
	

	@Override
	public boolean modifyBankCard(BankCard bankCard) {
		return bankCardMapper.updateByPrimaryKey(bankCard) > 0;
	}

	@Override
	public List<PayGate> getPayGateList() {
		PayGateExample exp = new PayGateExample();
		Pager<PayGate> pager = new Pager<PayGate>();
		return payGateMapper.selectByExample(exp, pager);
	}

	/**
	 * 保存支付通知日志
	 *
	 * @param log
	 *            支付通知日志
	 * @return
	 */
	public boolean savePayNotifyLog(PayNotifyLog log) {
		try {
			log.setCreateDate(new Date());
			pnl.save(log);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return true;
	}

	@Override
	public boolean isExist(String cardNumber) {

		BankCardExample example = new BankCardExample();
		example.appendCriterion("cardNumber =", cardNumber);

		return this.bankCardMapper.countByExample(example) > 0;
	}

	@Override
	public List<BankCard> findBankCardsByUserId(Long userId) {

		BankCardExample example = new BankCardExample();
		example.appendCriterion("user_id =", userId);
		Pager<BankCard> pager = new Pager<>();
		pager.setPageSize(100);
		return this.bankCardMapper.selectByExample(example, pager);
	}

	@Override
	public void unbindLLPay(Long bankCardId) throws BusinessException {

		BankCard bankCard = this.findBankCardById(bankCardId);
		if (bankCard == null) {
			throw new BusinessException("原银行卡不存在");
		}
		
		String agreeNo = LLPayUtil.queryAgreeNo(
				bankCard.getUser().getExternal(), bankCard.getCardNumber());
		
		logger.debug(String.format("用户外部ID:%s 银行卡号:%s 连连协议号:%s", 
				bankCard.getUser().getExternal(),
				bankCard.getCardNumber(),
				agreeNo));
		// 连连支付解除绑定
		if (StringUtils.isNotEmpty(agreeNo)) {
			boolean unbinded = LLPayUtil.bankcardUnbind(
					bankCard.getUser().getExternal(), agreeNo);
			if (!unbinded) {
				throw new BusinessException("连连支付解除绑定失败");
			} else {
				bankCard.setLlpayAgreeNo("");
				this.bankCardMapper.updateByPrimaryKey(bankCard);
				
				logger.debug(String.format("用户外部ID:%s 银行卡号:%s 连连协议号:%s 解绑连连成功", 
						bankCard.getUser().getExternal(),
						bankCard.getCardNumber(),
						agreeNo));
			}
		} else {
			bankCard.setLlpayAgreeNo("");
			this.bankCardMapper.updateByPrimaryKey(bankCard);
		}
	}

	/**
	 * 修改银行信息
	 *
	 * @param bankInfo
	 * @return
	 */
	public boolean modifyBankInfo(BankInfo bankInfo) {
		BankInfo bank = bankInfoMapper.selectByPrimaryKey(bankInfo.getId());
		bank.setModifyDate(new Date());
		bank.setPayGate(bankInfo.getPayGate());
		bank.setMaxPayInfo(bankInfo.getMaxPayInfo());
		bank.setPayBankCode(bankInfo.getPayBankCode());

		if ("LLPay".equals(bankInfo.getPayGate())) {
			bank.setPayBankCode(bank.getBankCode());
		} else if ("UMPay".equals(bankInfo.getPayGate())) {
			if ("01050000".equals(bank.getBankCode())) {
				bank.setPayBankCode("CCB");
			} else if ("01030000".equals(bank.getBankCode())) {
				bank.setPayBankCode("ABC");
			} else if ("01040000".equals(bank.getBankCode())) {
				bank.setPayBankCode("BOC");
			} else if ("03020000".equals(bank.getBankCode())) {
				bank.setPayBankCode("CITIC");
			} else if ("03030000".equals(bank.getBankCode())) {
				bank.setPayBankCode("CEB");
			} else if ("03090000".equals(bank.getBankCode())) {
				bank.setPayBankCode("CIB");
			} else {
				return false;
			}
		}
		return bankInfoMapper.updateByPrimaryKey(bank) > 0;
	}

	/**
	 * 查找银行信息
	 *
	 * @return
	 */

	public List<BankInfo> findAllBankInfo() {
		Pager<BankInfo> pager = new Pager<BankInfo>();
		pager.setPageSize(Pager.MAX_PAGE_SIZE);
		BankInfoExample exp = new BankInfoExample();

		return bankInfoMapper.selectByExample(exp, pager);
	}

	@Override
	public BankInfo getBankInfoById(Long id) {
		return bankInfoMapper.selectByPrimaryKey(id);
	}

	/**
	 * 根据银行编码获取银行信息
	 *
	 * @param bankCode
	 * @return
	 */
	public BankInfo getBankInfoByBankCode(String bankCode) {
		if (bankCode == null) {
			return null;
		}
		BankInfoExample exp = new BankInfoExample();
		exp.appendCriterion("bankCode=", bankCode);
		return bankInfoMapper.selectOneByExample(exp);
	}

	@Override
	public Pager<BankInfo> findAllBankInfo(Pager<BankInfo> pager) {
		return findAllBankInfo(null, pager);
	}

	@Override
	public Pager<BankInfo> findAllBankInfo(BankInfoExample example,
			Pager<BankInfo> pager) {
		if (example == null) {
			example = new BankInfoExample();
			example.setOrderByClause("id desc");
		}
		pager.setPageSize(50);
		pager.setList(bankInfoMapper.selectByExample(example, pager));
		pager.setTotalCount(bankInfoMapper.countByExample(example));
		return pager;
	}

	@Override
	public boolean saveBankInfo(BankInfo bankInfo) {
		bankInfo.setCreateDate(new Date());
		return bankInfoMapper.insert(bankInfo) > 0;
	}

	@Override
	public boolean deleteBankInfo(Long id) {
		BankInfo bankInfo = bankInfoMapper.selectByPrimaryKey(id);
		return bankInfoMapper.deleteByPrimaryKey(bankInfo) > 0;
	}

	@Override
	public boolean updateBankInfo(BankInfo bankInfo) {
		BankInfo bankInfo2 = bankInfoMapper
				.selectByPrimaryKey(bankInfo.getId());
		bankInfo2.setModifyDate(new Date());
		bankInfo2.setBankName(bankInfo.getBankName());
		bankInfo2.setBankCode(bankInfo.getBankCode());
		bankInfo2.setBindable(bankInfo.getBindable());
		if (bankInfo.getWebPaygate() == null) {
			bankInfo2.setWebPaygate(new PayGate());
		} else {
			bankInfo2.setWebPaygate(bankInfo.getWebPaygate());
		}
		if (bankInfo.getH5Paygate() == null) {
			bankInfo2.setH5Paygate(new PayGate());
		} else {
			bankInfo2.setH5Paygate(bankInfo.getH5Paygate());
		}
		if (bankInfo.getAndroidPaygate() == null) {
			bankInfo2.setAndroidPaygate(new PayGate());
		} else {
			bankInfo2.setAndroidPaygate(bankInfo.getAndroidPaygate());
		}
		if (bankInfo.getiOSPaygate() == null) {
			bankInfo2.setiOSPaygate(new PayGate());
		} else {
			bankInfo2.setiOSPaygate(bankInfo.getiOSPaygate());
		}
		return bankInfoMapper.updateByPrimaryKey(bankInfo2) > 0;
	}

	@Override
	@Transactional
	public boolean updatePayInfo(Long id, String payNumber, BankCard bankcard,
			Order.Status status) {
		Order order = orderMapper.selectByPrimaryKey(id);
		order.setPayNumber(payNumber);
		order.setBankcard(bankcard);
		order.setModifyDate(new Date());
		if (Order.Status.STATUS_FAILED.equals(status)) {
			if(Order.Status.STATUS_UNPAY.equals(order.getStatus())||Order.Status.STATUS_CONFIRM.equals(order.getStatus())){
				if(orderMapper.updateLockOrderById(order.getId())<=0){
					commonService.setMongodbForValue(String.format(MONGODB_KEY_LOCK_ORDER_FAILED, order.getOrderNumber()), formatDateTime(new Date()));
				} else {
					order.setStatus(status);
					productMapper.updateAfterReleaseOrder(order.getAmount(), order
							.getProduct().getId());
					orderMapper.updateByPrimaryKey(order);
				}
			}
		} else {
			order.setStatus(status);
			orderMapper.updateByPrimaryKey(order);
		}
		// 如果是支付失败的情况就把金额类似过期一样释放出来
//		if (Order.Status.STATUS_FAILED.equals(order.getStatus())) {
//			if(orderMapper.updateLockOrderById(order.getId())<=0){
//				commonService.setMongodbForValue(String.format(MONGODB_KEY_LOCK_ORDER_FAILED, order.getOrderNumber()), formatDateTime(new Date()));
//			} else {
//				productMapper.updateAfterReleaseOrder(order.getAmount(), order
//						.getProduct().getId());
//			}
//		}
		return true;
	}

	@Override
	public List<BankCard> findBankCardByUser(User user) {
		BankCardExample example = new BankCardExample();
		example.appendCriterion("user_id=", user.getId());
		example.appendCriterion("status=", BankCard.Status.BINDED);
		example.setOrderByClause("lastTime desc");
		return this.bankCardMapper.selectByExample(example, null);
	}

	@Override
	public List<BankCard> findAllBankCardByUser(User user) {
		BankCardExample example = new BankCardExample();
		example.setOrderByClause("createDate desc");
		example.appendCriterion("user_id=", user.getId());
		return this.bankCardMapper.selectByExample(example, null);
	}

	@Override
	public BankCard findBankCardById(Long id) {
		return bankCardMapper.selectByPrimaryKey(id);
	}

	@Override
	public BankCard findBankCardByCardNumber(String cardNumber, Long id) {
		BankCardExample example = new BankCardExample();
		example.appendCriterion("cardNumber=", cardNumber);
		example.appendCriterion("user_id=", id);
		List<BankCard> list = bankCardMapper.selectByExample(example, null);
		return list.size() > 0 ? list.get(0) : null;
	}

	@Override
	public void setFinalPayStatus(String orderNumber, boolean isSuccess) {
		redisTemplate.opsForValue().set("ORDER_PAY_STATUS_" + orderNumber,
				isSuccess, 2, TimeUnit.HOURS);
	}

	@Override
	public Boolean getFinalPayStatus(String orderNumber) {
		return (Boolean) redisTemplate.opsForValue().get(
				"ORDER_PAY_STATUS_" + orderNumber);
	}
	
	public boolean supplyOrder(String orderNumber) {
		OrderExample example = new OrderExample();
		example.appendCriterion("`orderNumber`=", orderNumber);
		Order order = orderService.findOneOrder(example);
		if(order != null && Order.Status.STATUS_OVERDUE.equals(order.getStatus())){
			Date now = new Date();
			if(orderMapper.updateLockOrderById(order.getId())<=0){
				commonService.setMongodbForValue(String.format(MONGODB_KEY_LOCK_ORDER_FAILED, order.getOrderNumber()), formatDateTime(now));
				return true;
			}
			
			// 更新用户的认证信息
			User user = order.getUser();
			BankCard bankCard = order.getBankcard();
			user.setIdCard(bankCard.getCertId());
			user.setRealName(bankCard.getUserName());
			user.setModifyDate(now);
			userMapper.updateByPrimaryKey(user);
			
			order.setModifyDate(now);
			order.setStatus(Order.Status.STATUS_PAID);
			orderMapper.updateByPrimaryKey(order);
			
			Product product = productMapper.selectByPrimaryKey(order.getProduct()
					.getId());
			
			// 添加金融包 以后的计算利息就靠它了
			Financing financing = new Financing();
			financing.setProduct(product);
			financing.setName(product.getName());
			financing.setTerm(product.getTerm());
			financing.setMinTerm(product.getMinTerm());
			financing.setInterestRate(product.getFinalRate());
			financing.setValueDate(getMaxDate(order.getCreateDate(), product.getValueDate()));
			financing.setAmount(order.getAmount());
			financing.setUser(order.getUser());
			financing.setCreateDate(order.getCreateDate());
			financing.setModifyDate(financing.getCreateDate());
			financing.setSettlementDate(calculateSettlementDate(
					financing.getValueDate(), financing.getTerm()));
			financing.setStatus(Financing.Status.STATUS_DEFAULT);
			financing.setOrder(order);
			financing.setPayGateCode(order.getPayGateCode());
			financing.setIncome(new BigDecimal(0));
			financingMapper.insert(financing);			
			
			if(financing.getId()!=null){
				switch (financing.getProduct().getCategory()) {
				case CURRENT:
					if(!isEmpty(financing.getProduct().getEarningsRules())){
						for(int i=0;i<financing.getProduct().getEarningsRules().size();i++){
							ProductEarningsRule rule = financing.getProduct().getEarningsRules().get(i);
							
							FinancingIncomeRule incomeRule = new FinancingIncomeRule();
							incomeRule.setCreateDate(order.getCreateDate());
							incomeRule.setModifyDate(order.getCreateDate());
							incomeRule.setFinancing(financing);
							incomeRule.setHoldingTime(rule.getHoldingTime());
							incomeRule.setInterestRate(rule.getFinalInterestRate());
							incomeRule.setDueDate(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1)));
							incomeRule.setRedemptionStartTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4-7)));
							incomeRule.setRedemptionEndTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4)));
							incomeRule.setStage(i+1);
							incomeRule.setLast(i == financing.getProduct().getEarningsRules().size()-1);
							financingIncomeRuleMapper.insert(incomeRule);
						}
					}
					break;
				default:
					break;
				}
			}
			creditService.calculateProductCredits(financing);
			financingService.generateAgreement(financing);
		}
		return true;
	}
	
	@Override
	@Transactional
	public boolean payOrderManual(Order order){
		order = orderMapper.selectByPrimaryKey(order.getId());
		if (Order.Status.STATUS_PAID.equals(order.getStatus())
				|| Order.Status.STATUS_FAILED.equals(order.getStatus())
				|| Order.Status.STATUS_EXCESS.equals(order.getStatus())) {
			return true;
		}
		Date now = new Date();
		if(orderMapper.updateLockOrderById(order.getId())<=0){
			commonService.setMongodbForValue(String.format(MONGODB_KEY_LOCK_ORDER_FAILED, order.getOrderNumber()), formatDateTime(now));
			return true;
		}
		boolean isExcess = false;
		// 调用支付的方法
		this.pay();
		// 更新用户的认证信息
		User user = order.getUser();
		if(user!=null){
			BankCard bankCard = order.getBankcard();
			if(bankCard!=null){
				if(BankCard.Status.UNBIND.equals(bankCard.getStatus())){
					bankCard.setStatus(BankCard.Status.BINDED);
					bankCardMapper.updateByPrimaryKey(bankCard);
				}
				user.setIdCard(bankCard.getCertId());
				user.setRealName(bankCard.getUserName());
				user.setModifyDate(now);
				userMapper.updateByPrimaryKey(user);
			}
		}
		Product product = productMapper.selectByPrimaryKey(order.getProduct()
				.getId());
		if (Order.Status.STATUS_OVERDUE.equals(order.getStatus())) {
			// 判断产品是否还有剩余的金额
			if (product.getTotalAmount().doubleValue()
					- product.getSoldAmount().doubleValue() < order.getAmount()
					.doubleValue()) {
				order.setModifyDate(now);
				order.setStatus(Order.Status.STATUS_EXCESS);
				orderMapper.updateByPrimaryKey(order);
				isExcess = true;
			} else {
				order.setModifyDate(now);
				order.setStatus(Order.Status.STATUS_PAID);
				orderMapper.updateByPrimaryKey(order);
				// 处理产品
				product.setModifyDate(now);
				product.setSoldAmount(product.getSoldAmount().add(
						order.getAmount()));
				productMapper.updateByPrimaryKey(product);
				productMapper.updateNumberOfShoppers(product);
			}
			logger.info("STATUS_OVERDUE===================>product_id="
					+ product.getId() + "&orderNumber="
					+ order.getOrderNumber() + "&orderAmount="
					+ order.getAmount() + "&productUnpayAmount="
					+ product.getUnpayAmount() + "&productSoldAmount="
					+ product.getSoldAmount());
		} else if (Order.Status.STATUS_CONFIRM.equals(order.getStatus())
				|| Order.Status.STATUS_UNPAY.equals(order.getStatus())) {
			order.setModifyDate(now);
			order.setStatus(Order.Status.STATUS_PAID);
			orderMapper.updateByPrimaryKey(order);
			// 处理产品
			logger.info("STATUS_UNPAY===================>product_id="
					+ product.getId() + "&orderNumber="
					+ order.getOrderNumber() + "&orderAmount="
					+ order.getAmount() + "&productUnpayAmount="
					+ product.getUnpayAmount() + "&productSoldAmount="
					+ product.getSoldAmount());
			productMapper.updateAfterPayOrder(order.getAmount(),
					product.getId());
			productMapper.updateNumberOfShoppers(product);
		}
		// 如果没有超额支付就走正常支付流程
		if (!isExcess) {
			// 添加金融包 以后的计算利息就靠它了
			Financing financing = new Financing();
			financing.setProduct(product);
			financing.setName(product.getName());
			financing.setTerm(product.getTerm());
			financing.setMinTerm(product.getMinTerm());
			financing.setInterestRate(product.getFinalRate());
			financing.setValueDate(getMaxDate(order.getCreateDate(), product.getValueDate()));
			financing.setAmount(order.getAmount());
			financing.setUser(order.getUser());
			financing.setCreateDate(order.getCreateDate());
			financing.setModifyDate(financing.getCreateDate());
			financing.setSettlementDate(calculateSettlementDate(
					financing.getValueDate(), financing.getTerm()));
			financing.setStatus(Financing.Status.STATUS_DEFAULT);
			financing.setOrder(order);
			financing.setPayGateCode(order.getPayGateCode());
			financing.setIncome(new BigDecimal(0));
			financing.setTrack(order.getTrack());
			financingMapper.insert(financing);
			
			if(financing.getId()!=null){
				switch (financing.getProduct().getCategory()) {
				case CURRENT:
					if(!isEmpty(financing.getProduct().getEarningsRules())){
						for(int i=0;i<financing.getProduct().getEarningsRules().size();i++){
							ProductEarningsRule rule = financing.getProduct().getEarningsRules().get(i);
							
							FinancingIncomeRule incomeRule = new FinancingIncomeRule();
							incomeRule.setCreateDate(order.getCreateDate());
							incomeRule.setModifyDate(order.getCreateDate());
							incomeRule.setFinancing(financing);
							incomeRule.setHoldingTime(rule.getHoldingTime());
							incomeRule.setInterestRate(rule.getFinalInterestRate());
							incomeRule.setDueDate(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1)));
							incomeRule.setRedemptionStartTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4-7)));
							incomeRule.setRedemptionEndTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4)));
							incomeRule.setStage(i+1);
							incomeRule.setLast(i == financing.getProduct().getEarningsRules().size()-1);
							financingIncomeRuleMapper.insert(incomeRule);
						}
					}
					break;
				default:
					break;
				}
			}			
			// 生成协议
			financingService.generateAgreement(financing);
			
			// 发送短信
			userService.sendSuccessMessage(financing);
		}
		return true;
	}

	@Override
	@Transactional
	public boolean payOrder(Order order, boolean devMode) {
		order = orderMapper.selectByPrimaryKey(order.getId());
		if (Order.Status.STATUS_PAID.equals(order.getStatus())
				|| Order.Status.STATUS_FAILED.equals(order.getStatus())
				|| Order.Status.STATUS_EXCESS.equals(order.getStatus())) {
			return true;
		}
		
		logger.info("payOrder");
		
		Date now = new Date();
		if(orderMapper.updateLockOrderById(order.getId())<=0){
			commonService.setMongodbForValue(String.format(MONGODB_KEY_LOCK_ORDER_FAILED, order.getOrderNumber()), formatDateTime(now));
			return true;
		}
		boolean isExcess = false;
		// 调用支付的方法
		this.pay();
		// 更新用户的认证信息
		
		logger.info("pay()");

		
		User user = order.getUser();
		BankCard bankCard = order.getBankcard();
		user.setIdCard(bankCard.getCertId());
		user.setRealName(bankCard.getUserName());
		user.setModifyDate(now);
		userMapper.updateByPrimaryKey(user);
		
		Product product = productMapper.selectByPrimaryKey(order.getProduct()
				.getId());
		if (Order.Status.STATUS_OVERDUE.equals(order.getStatus())) {
			// 判断产品是否还有剩余的金额
			if (product.getTotalAmount().doubleValue()
					- product.getSoldAmount().doubleValue() < order.getAmount()
					.doubleValue()) {
				order.setModifyDate(now);
				order.setStatus(Order.Status.STATUS_EXCESS);
				orderMapper.updateByPrimaryKey(order);
				isExcess = true;
			} else {
				order.setModifyDate(now);
				order.setStatus(Order.Status.STATUS_PAID);
				orderMapper.updateByPrimaryKey(order);
				// 处理产品
				product.setModifyDate(now);
				product.setSoldAmount(product.getSoldAmount().add(
						order.getAmount()));
				productMapper.updateByPrimaryKey(product);
				productMapper.updateNumberOfShoppers(product);
			}
			logger.info("STATUS_OVERDUE===================>product_id="
					+ product.getId() + "&orderNumber="
					+ order.getOrderNumber() + "&orderAmount="
					+ order.getAmount() + "&productUnpayAmount="
					+ product.getUnpayAmount() + "&productSoldAmount="
					+ product.getSoldAmount());
		} else if (Order.Status.STATUS_CONFIRM.equals(order.getStatus())
				|| Order.Status.STATUS_UNPAY.equals(order.getStatus())) {
			order.setModifyDate(now);
			order.setStatus(Order.Status.STATUS_PAID);
			orderMapper.updateByPrimaryKey(order);
			// 处理产品
			logger.info("STATUS_UNPAY===================>product_id="
					+ product.getId() + "&orderNumber="
					+ order.getOrderNumber() + "&orderAmount="
					+ order.getAmount() + "&productUnpayAmount="
					+ product.getUnpayAmount() + "&productSoldAmount="
					+ product.getSoldAmount());
			productMapper.updateAfterPayOrder(order.getAmount(),
					product.getId());
			productMapper.updateNumberOfShoppers(product);
		}
		// 如果没有超额支付就走正常支付流程
		if (!isExcess) {
			// 添加金融包 以后的计算利息就靠它了
			Financing financing = new Financing();
			financing.setProduct(product);
			financing.setName(product.getName());
			financing.setTerm(product.getTerm());
			financing.setMinTerm(product.getMinTerm());
			financing.setInterestRate(product.getFinalRate());
			financing.setValueDate(getMaxDate(order.getCreateDate(), product.getValueDate()));
			financing.setAmount(order.getAmount());
			financing.setUser(order.getUser());
			financing.setCreateDate(order.getCreateDate());
			financing.setModifyDate(financing.getCreateDate());
			financing.setSettlementDate(calculateSettlementDate(
					financing.getValueDate(), financing.getTerm()));
			financing.setStatus(Financing.Status.STATUS_DEFAULT);
			financing.setOrder(order);
			financing.setPayGateCode(order.getPayGateCode());
			financing.setIncome(new BigDecimal(0));
			financing.setTrack(order.getTrack());
			financingMapper.insert(financing);
			
			if(financing.getId()!=null){
				switch (financing.getProduct().getCategory()) {
				case CURRENT:
					if(!isEmpty(financing.getProduct().getEarningsRules())){
						for(int i=0;i<financing.getProduct().getEarningsRules().size();i++){
							ProductEarningsRule rule = financing.getProduct().getEarningsRules().get(i);
							
							FinancingIncomeRule incomeRule = new FinancingIncomeRule();
							incomeRule.setCreateDate(order.getCreateDate());
							incomeRule.setModifyDate(order.getCreateDate());
							incomeRule.setFinancing(financing);
							incomeRule.setHoldingTime(rule.getHoldingTime());
							incomeRule.setInterestRate(rule.getFinalInterestRate());
							incomeRule.setDueDate(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1)));
							incomeRule.setRedemptionStartTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4-7)));
							incomeRule.setRedemptionEndTime(formatDate(addDays(financing.getValueDate(), incomeRule.getHoldingTime()-1-4)));
							incomeRule.setStage(i+1);
							incomeRule.setLast(i == financing.getProduct().getEarningsRules().size()-1);
							financingIncomeRuleMapper.insert(incomeRule);
						}
					}
					break;
				default:
					break;
				}
			}
			
			// 增加积分
//			creditService.calculateProductCredits(financing);
			// 发送短信
			
			financingService.generateAgreement(financing);
			
			userService.sendSuccessMessage(financing);
//			try {
//				this.messageService.sendAppMessage(user, Message.CATEGORY_TRADE, 
//						String.format("尊敬的%s，您已成功购买%s%s元，可到[我的资产]查看资产详情。客服热线：400-871-8080",
//								user.getRealName(),
//								financing.getName(),
//								financing.getAmount().intValue()),
//						null);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
			MessageEvent event = new MessageEvent(
					EventConstant.KEY_PAY_SUCCESS_EVENT, financing.getId());
			event.arg1 = devMode;
			CommonServiceImpl.applicationContext.publishEvent(event);
		}
		return true;
	}


	/**
	 * 真正支付的方法
	 */
	private void pay() {

	}

	@Override
	public boolean saveBankCard(BankCard bankcard) {
		if (bankcard.getId() == null) {
			/*
			 * 防脏读判断
			 */
			BankCard card = findBankCardByCardNumber(bankcard.getCardNumber(),bankcard.getUser().getId());
			if (card != null) {
				return false;
			}
			// 设置默认值
			bankcard.setCertType(BankCard.CertType.ID_CARD);
			bankcard.setCardType(BankCard.CardType.CARD);
			bankcard.setCreateDate(new Date());
			bankcard.setModifyDate(new Date());

			return bankCardMapper.insert(bankcard) > 0;
		} else {
			bankcard.setModifyDate(new Date());
			return bankCardMapper.updateByPrimaryKey(bankcard) > 0;
		}
	}

	@Override
	public Pager<BankMaintain> findAllBankMaintain(Pager<BankMaintain> pager) {
		return findAllBankMaintain(pager, new BankMaintainExample());
	}

	@Override
	public Pager<BankMaintain> findAllBankMaintain(Pager<BankMaintain> pager,
			BankMaintainExample example) {
		example.setOrderByClause("id desc");
		pager.setList(bankMaintainMapper.selectByExample(example, pager));
		pager.setTotalCount(bankMaintainMapper.countByExample(example));
		return pager;
	}

	@Override
	public boolean saveBankMaintain(BankMaintain bankMaintain) {
		bankMaintain.setCreateDate(new Date());
		bankMaintain.setStatus("will");
		BankInfo bankInfo = getBankInfoByBankCode(bankMaintain.getBankCode());
		bankMaintain.setBankName(bankInfo.getBankName());
		return bankMaintainMapper.insert(bankMaintain) > 0;
	}

	@Override
	public BankMaintain getBankMaintainById(Long id) {
		return bankMaintainMapper.selectByPrimaryKey(id);
	}

	@Override
	public boolean updateBankMaintain(BankMaintain bankMaintain) {
		BankMaintain bankMaintain2 = bankMaintainMapper
				.selectByPrimaryKey(bankMaintain.getId());
		bankMaintain2.setModifyDate(new Date());
		bankMaintain2.setBankCode(bankMaintain.getBankCode());
		bankMaintain2.setStartDate(bankMaintain.getStartDate());
		bankMaintain2.setStartTime(bankMaintain.getStartTime());
		bankMaintain2.setEndTime(bankMaintain.getEndTime());
		bankMaintain2.setRepeattimes(bankMaintain.getRepeattimes());
		BankInfo bankInfo = getBankInfoByBankCode(bankMaintain.getBankCode());
		bankMaintain2.setBankName(bankInfo.getBankName());
		return bankMaintainMapper.updateByPrimaryKey(bankMaintain2) > 0;
	}

	@Override
	public boolean deleteBankMaintain(Long id) {
		BankMaintain bankMaintain = bankMaintainMapper.selectByPrimaryKey(id);
		return bankMaintainMapper.deleteByPrimaryKey(bankMaintain) > 0;
	}

	@Override
	public boolean isBankMaintain(String bankCode) {

		boolean flag = false;
		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
		String now = sdf.format(new Date());
		String nowDate = sdf2.format(new Date());

		/*
		 * 改变已过期的维护的状态
		 */
		List<BankMaintain> overList = bankMaintainMapper
				.findOverdueBankMaintain(nowDate, now);
		for (int i = 0; overList != null && i < overList.size(); i++) {
			overList.get(i).setStatus("done");
			overList.get(i).setModifyDate(new Date());
			bankMaintainMapper.updateByPrimaryKey(overList.get(i));
		}

		BankMaintainExample example = new BankMaintainExample();
		example.appendCriterion("bankCode=", bankCode);
		example.appendCriterion("startDate<=", nowDate);
		example.appendCriterion("status!=", "done");
		Pager<BankMaintain> pager = new Pager<BankMaintain>();
		pager.setList(bankMaintainMapper.selectByExample(example, pager));
		pager.setTotalCount(bankMaintainMapper.countByExample(example));

		if (pager.getPageCount() > 0) {
			List<BankMaintain> list = pager.getList();
			for (int i = 0; list != null && i < list.size(); i++) {
				BankMaintain maintain = list.get(i);
				/*
				 * 判断当前时间是否在开始时间和结束时间之间
				 */
				if (maintain.getStartTime().compareTo(now) > 0) {
					continue;
				} else if (maintain.getStartTime().compareTo(now) < 0
						&& maintain.getEndTime().compareTo(now) > 0) {
					maintain.setStatus("doing");
					maintain.setModifyDate(new Date());
					flag = bankMaintainMapper.updateByPrimaryKey(maintain) > 0;
				} else if (maintain.getEndTime().compareTo(now) < 0) {
					if ("one".equals(maintain.getRepeattimes())) {
						maintain.setStatus("done");
						maintain.setModifyDate(new Date());
						bankMaintainMapper.updateByPrimaryKey(maintain);
						continue;
					}
				}
			}
		}
		return flag;
	}

	@Override
	public List<BankCard> findBindedBankCardsByUserId(Long userId) {
		BankCardExample example = new BankCardExample();
		example.appendCriterion("status ='BINDED'");
		example.appendCriterion("user_id =", userId);
		Pager<BankCard> pager = new Pager<>();
		pager.setPageSize(100);
		return this.bankCardMapper.selectByExample(example, pager);
	}

	@Override
	public void unbindBankCard(Long bankCardId) throws BusinessException {
		
		this.unbindLLPay(bankCardId);
		
		BankCard bankCard = this.findBankCardById(bankCardId);
		if (bankCard == null) {
			throw new BusinessException("原银行卡不存在");
		}
		
		bankCard.setStatus(BankCard.Status.UNBIND);
		if(this.bankCardMapper.updateByPrimaryKey(bankCard) < 1){
			throw new BusinessException("更新银卡错误");
		}
	}

	@Override
	public void changeBankCard(Long originalBankCardId, Long newBankCardId) throws BusinessException {
		
		if(originalBankCardId.equals(newBankCardId)){
			throw new BusinessException("原银行卡与新银行卡相同");
		}
		
		BankCard originalBankCard = this.findBankCardById(originalBankCardId);
		BankCard newBankCard = this.findBankCardById(newBankCardId);
		if (originalBankCard == null) {
			throw new BusinessException("原银行卡不存在");
		}
		if (newBankCard == null) {
			throw new BusinessException("新银行卡不存在");
		}
		
		// 验证是否可以换卡
		checkOriginalBankCard(originalBankCard);
			
		// 更换订单银行卡
		List<Order> orders = this.orderMapper.findNotRepaymentOrdersByBankCardId(originalBankCardId);
		for(Order order : orders){
			changeOrderBankCard(order, newBankCard);
		}
		
		// 解绑银行卡
		this.unbindBankCard(originalBankCardId);
	}

	/**
	 * 更换订单银行卡
	 * @param order			订单
	 * @param newBankCard	新银行卡
	 * @throws BusinessException
	 */
	private void changeOrderBankCard(Order order, BankCard newBankCard) throws BusinessException {
		
		// 检查
		if(!newBankCard.getStatus().equals(BankCard.Status.BINDED)){
			throw new BusinessException("新银行卡未绑定");
		}
		
		if(!order.getBankcard().getUser().getId().equals(newBankCard.getUser().getId())){
			throw new BusinessException("新银行卡用户与原卡不同");
		}
		
		if(!order.getBankcard().getUserName().equals(newBankCard.getUserName())){
			throw new BusinessException("新银行卡开卡人姓名与原卡不一致");
		}
		
		OrderBankCardChange orderBankCardChange = new OrderBankCardChange();
		orderBankCardChange.setOrder(order);
		orderBankCardChange.setOriginalBankCard(order.getBankcard());
		orderBankCardChange.setNewBankCard(newBankCard);
		orderBankCardChange.setCreateDate(new Date());
		orderBankCardChange.setModifyDate(new Date());
		this.orderBankCardChangeMapper.insert(orderBankCardChange);
		
		order.setBankcard(newBankCard);
		orderMapper.updateByPrimaryKey(order);
	}

	/**
	 * 检查原银行卡
	 * @param originalBankCard	原银行卡
	 * @throws BusinessException 
	 */
	private void checkOriginalBankCard(BankCard originalBankCard) throws BusinessException {
		
		// 银行卡订单是否已经申请打款或打款未完毕
		RepaymentOrderExample example = new RepaymentOrderExample();
		example.appendCriterion("bankcard_id =", originalBankCard.getId());
		example.appendCriterion("status not in ('STATUS_SUCCESS', 'STATUS_FAILURE')");
		if(this.repaymentOrderMapper.countByExample(example) > 0){
			throw new BusinessException("银行卡存在申请打款未完毕的还款订单");
		}
	}

	@Override
	public Pager<BankCard> findBankCardsByKeyword(String keyword, Pager<BankCard> pager) {
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("keyword", keyword);
		map.put("startNumber", pager.getStartNumber());
		map.put("pageSize", pager.getPageSize());
		
		pager.setList(this.bankCardMapper.selectBankCardsByKeyword(map));
		pager.setTotalCount(this.bankCardMapper.countBankCardsByKeyword(map));
		
		return pager;
	}

	@Override
	public void savePayNotifyLog(String payGate, String type, String content) {

		PayNotifyLog log = new PayNotifyLog();
		log.setPayGate(payGate);
		log.setNotifyType(type);
		log.setContent(content);
		this.savePayNotifyLog(log);
	}
	
	@Override
	public Long getBankCardDayExceedAmount(BankCard bankCard, PayGateBank payGateBank, Long amount) {
		
		if (payGateBank.getDayLimit() == null
		|| payGateBank.getDayLimit() == 0) {
			return 0L;
		}
		
		PayGate payGate = this.getPayGateById(payGateBank.getPaygateid());
		
		Date now = new Date();
		Date startTime = DateTimeUtil.getDateDay(now);
		Date endTime = DateTimeUtil.getDateAndMaxTime(now);
		
		Long paidAmount = this.bankCardMapper.countPayGateBankCardPaidAmountByDate(
				bankCard.getId(),
				payGate.getGateCode(),
				startTime,
				endTime);
		
		Long totalAmount = amount;
		if(paidAmount != null){
			totalAmount += paidAmount;
		}
		
		return totalAmount - payGateBank.getDayLimit();
	}

	@Override
	public Long getBankCardMonthExceedAmount(BankCard bankCard, PayGateBank payGateBank, Long amount) {
		
		if(payGateBank.getMonthLimit() == null
		|| payGateBank.getMonthLimit() == 0){
			return 0L;
		}
		
		PayGate payGate = this.getPayGateById(payGateBank.getPaygateid());
		
		DateTime now = new DateTime();
		Date startTime = now.dayOfMonth().withMinimumValue().toLocalDate().toDate();
		Date endTime = DateTimeUtil.getDateAndMaxTime(now.dayOfMonth().withMaximumValue().toDate());
		
		Long paidAmount = this.bankCardMapper.countPayGateBankCardPaidAmountByDate(
				bankCard.getId(),
				payGate.getGateCode(),
				startTime,
				endTime);
		
		Long totalAmount = amount;
		if(paidAmount != null){
			totalAmount += paidAmount;
		}
		
		return totalAmount - payGateBank.getMonthLimit();
	}

	@Override
	public boolean isPayNotifyHandled(Order order) {
		
		// 支付通知已处理
		if (Order.Status.STATUS_PAID.equals(order.getStatus())
		|| Order.Status.STATUS_FAILED.equals(order.getStatus())
		|| Order.Status.STATUS_EXCESS.equals(order.getStatus())) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public boolean payNotifySuccess(Order order, boolean devMode) {
		
		if (this.isPayNotifyHandled(order)) {
			return false;
		}
		
		// 支付成功绑定银行卡
		BankCard bankcard = order.getBankcard();
		if (bankcard.getStatus().equals(Status.UNBIND)) {
			bankcard.setStatus(Status.BINDED);
			this.saveBankCard(bankcard);
		}

		this.payOrder(order, devMode);
		this.setFinalPayStatus(order.getOrderNumber(), true);

		// 刷新用户
		User user = this.userMapper.selectByPrimaryKey(order.getUser().getId());
		this.messageService.sendAppMessage(user, Message.CATEGORY_TRADE, 
				String.format("尊敬的%s，您已成功购买%s%s元，可到[我的资产]查看资产详情。客服热线：400-871-8080",
						user.getRealName(),
						order.getProduct().getName(),
						new DecimalFormat(",##0.00").format(order.getAmount())),
				null);
		
		return true;
	}

	@Override
	public void payNotifyFailure(Order order) {
		
		if (this.isPayNotifyHandled(order)) {
			return;
		}
		
		// 设置订单为失败状态
		this.updatePayInfo(
				order.getId(),
				order.getPayNumber(),
				order.getBankcard(),
				Order.Status.STATUS_FAILED);
		this.setFinalPayStatus(order.getOrderNumber(), false);
	}

	@Override
	public RepaymentOrder findRepaymentOrderByOrderNumber(String orderNumber) {
		RepaymentOrderExample example = new RepaymentOrderExample();
		example.appendCriterion("orderNumber=", orderNumber);
		return repaymentOrderMapper.selectOneByExample(example);
	}
	
	@Override
	public void repayNotifySuccess(Executor executor, String orderNumber) {
		
		final RepaymentOrder repaymentOrder = this.findRepaymentOrderByOrderNumber(orderNumber);
		
		// 防止重复处理
		if (repaymentOrder.getStatus() == RepaymentOrder.Status.STATUS_SUCCESS
		|| repaymentOrder.getStatus() == RepaymentOrder.Status.STATUS_FAILURE) {
			return;
		}
		
		repaymentOrder.setStatus(RepaymentOrder.Status.STATUS_SUCCESS);
		repaymentOrder.setModifyDate(new Date());
		repaymentOrderMapper.updateByPrimaryKey(repaymentOrder);
		
		final DecimalFormat format = new DecimalFormat(",##0.00");
		if (StringUtils.isEmpty(repaymentOrder.getFinancingIds())) {
			
			// 红包提现还款
			executor.execute(new Runnable() {
				
				@Override
				public void run() {
					
					// 编辑消息内容
					String cardNo = repaymentOrder.getBankcard().getCardNumber();
					String lastCardNo = cardNo.substring(cardNo.length() - 4);
					User sendee = repaymentOrder.getBankcard().getUser();
					
					// 短信关键字替换
					String description = repaymentOrder.getDescription();
					String message = "尊敬的" + sendee.getRealName() + "，" + description
							+ format.format(repaymentOrder.getAmount())
							+ "元已打款至（尾号" + lastCardNo + "）卡中,请注意查收！客服热线:400-871-8080";
					
					// 发送App消息
					messageService.sendAppMessage(
						repaymentOrder.getBankcard().getUser(),
						Message.CATEGORY_BONUS, message, null);
					
					// 发送短信
					SMS sms = new SMS();
					sms.setMobile(sendee.getMobile());
					sms.setMessage(message);
					sms.setChannel("alauda_repayment");
					smsService.sendSMS(sms);
				}});
		} else {
			// 资产到期还款
			
			// 更新金融包状态
			String[] id = repaymentOrder.getFinancingIds().split(RepaymentOrder.FINANCING_ID_SEPARATOR);
			for (int i = 0; id != null && i < id.length; i++) {
				logger.debug("更新金融包:" + id[i]);
				Financing financing = this.financingMapper.selectByPrimaryKey(new Long(id[i]));
				financing.setModifyDate(new Date());
				financing.setStatus(Financing.Status.STATUS_REPAID);
				boolean up = financingMapper.updateByPrimaryKey(financing) > 0;
				logger.debug("更新金融包状态结果:" + up);
			}
			
			executor.execute(new Runnable() {

				@Override
				public void run() {
					
					// 编辑消息内容
					String cardNo = repaymentOrder.getBankcard().getCardNumber();
					String lastCardNo = cardNo.substring(cardNo.length() - 4);
					User sendee = repaymentOrder.getBankcard().getUser();
					
					// 短信关键字替换
					String name = repaymentOrder.getDescription();
					name = name.replaceAll("票据", "银票");
					String message = "尊敬的" + sendee.getRealName() + "，您购买的[" + name
							+ "]已到期，本息" + format.format(repaymentOrder.getAmount()) + "元已还款至（尾号"
							+ lastCardNo + "）卡中，请注意查收！客服热线:400-871-8080";
					
					// 发送App消息
					messageService.sendAppMessage(
							repaymentOrder.getBankcard().getUser(),
							Message.CATEGORY_TRADE, message, null);
					
					// 发送短信
					SMS sms = new SMS();
					sms.setMobile(sendee.getMobile());
					sms.setMessage(message);
					sms.setChannel("alauda_repayment");
					smsService.sendSMS(sms);
				}});
		}
	}

	@Override
	public void repayNotifyFailure(String orderNumber) {
		
		RepaymentOrder repaymentOrder = this.findRepaymentOrderByOrderNumber(orderNumber);
		
		// 防止重复处理
		if (repaymentOrder.getStatus() == RepaymentOrder.Status.STATUS_SUCCESS
		|| repaymentOrder.getStatus() == RepaymentOrder.Status.STATUS_FAILURE) {
			return;
		}
		
		repaymentOrder.setStatus(RepaymentOrder.Status.STATUS_FAILURE);
		repaymentOrder.setModifyDate(new Date());
		repaymentOrderMapper.updateByPrimaryKey(repaymentOrder);
	}

	@Override
	public void applyBonusRepay(Long bonusOrderId) {
		
		// 检查红包
		BonusOrder bonusOrder = this.bonusOrderMapper.selectByPrimaryKey(bonusOrderId);
		if(bonusOrder.getInPay() != null
		&& bonusOrder.getInPay()) {
			throw new RuntimeException("红包已申请打款");
		}
		
		if(bonusOrder.getRepayOrder() != null) {
			throw new RuntimeException("红包已申请打款");
		}
		
		if(bonusOrder.getRepaid()) {
			throw new RuntimeException("红包已打款");
		}
		
		// 查询用户当天是否有同类红包申请打款，没有则创建还款订单，有则累加金额到当天还款订单
		RepaymentOrder repaymentOrder = this.repaymentOrderMapper.findUserTodayAppliedBonusRepaymentOrder(
				bonusOrder.getOrder().getUser().getId(),
				bonusOrder.getBonusRecord().getCode());
		Redpacket redpacket = redEnvelopeService.getRedpacketByCode(bonusOrder.getBonusRecord().getCode());
		
		if (repaymentOrder == null) {
			// 创建还款订单
			BankCard bankcard = bonusOrder.getOrder().getBankcard();
			repaymentOrder = new RepaymentOrder();
			repaymentOrder.setAmount(bonusOrder.getAmount().doubleValue());
			repaymentOrder.setBankcard(bankcard);
			repaymentOrder.setCreateDate(new Date());
			repaymentOrder.setModifyDate(new Date());
			repaymentOrder.setFinancingIds(""); // 单独红包打款时，资产设为空
			repaymentOrder.setCardNumber(bankcard.getCardNumber());
			repaymentOrder.setBankName(bankcard.getBankName());
			repaymentOrder.setUserName(bonusOrder.getOrder().getUser().getRealName());
			repaymentOrder.setDescription(String.format("%s1笔", redpacket.getName()));
			repaymentOrder.setUserId(bonusOrder.getOrder().getUser().getId());
			DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
			repaymentOrder.setOrderNumber(String.format("HB%s%s", dateFormat.format(bonusOrder.getCreateDate()), bonusOrder.getId()));
			repaymentOrder.setStatus(RepaymentOrder.Status.STATUS_APPLY);
			
			if (repaymentOrderMapper.insert(repaymentOrder) <= 0) {
				throw new RuntimeException("插入红包还款订单失败");
			}
			
			this.updateBonusOrderAppliedRepay(bonusOrder, repaymentOrder);
		} else {
			// 累加红包金额到当天还款订单
			this.updateBonusOrderAppliedRepay(bonusOrder, repaymentOrder);
			this.sumRepaymentOrderBonusAmount(repaymentOrder, redpacket);
		}
	}
	
	/**
	 * 累计还款订单总红包打款金额
	 * @param repaymentOrder 还款订单
	 * @param redpacket 红包策略
	 */
	private void sumRepaymentOrderBonusAmount(RepaymentOrder repaymentOrder, Redpacket redpacket) {
		
		BonusOrderExample example = new BonusOrderExample();
		example.appendCriterion("repayOrder_id =", repaymentOrder.getId());
		List<BonusOrder> bonusOrders = this.bonusOrderMapper.selectByExample(example, null);
		BigDecimal amount = BigDecimal.ZERO;
		for(BonusOrder bonusOrder: bonusOrders) {
			amount = amount.add(bonusOrder.getAmount());
		}
		
		repaymentOrder.setAmount(amount.doubleValue());
		repaymentOrder.setDescription(String.format("%s%s笔",
				redpacket.getName(), bonusOrders.size()));
		repaymentOrder.setModifyDate(new Date());
		if (this.repaymentOrderMapper.updateByPrimaryKey(repaymentOrder) < 1) {
			throw new RuntimeException("更新还款订单红包金额失败");
		}
	}
	
	/**
	 * 更新红包订单为已申请打款状态
	 * @param bonusOrder	红包订单
	 * @param repaymentOrder	还款订单
	 */
	private void updateBonusOrderAppliedRepay(BonusOrder bonusOrder, RepaymentOrder repaymentOrder) {
		bonusOrder.setInPay(true);
		bonusOrder.setRepayOrder(repaymentOrder);
		bonusOrder.setModifyDate(new Date());
		if (this.bonusOrderMapper.updateByPrimaryKey(bonusOrder) < 1) {
			throw new RuntimeException("更新红包订单为申请打款失败");
		}
	}

	@Override
	public void updateOrderPayGateStatus(Long orderId, String payGateStatus) {
		
		if (this.orderMapper.updateOrderPayGateStatus(orderId, payGateStatus) < 1) {
			throw new RuntimeException("更新订单支付状态失败");
		}
	}

	@Override
	public void syncLLPayBankStatusAndLimit(JSONArray bankList) {
		
		/**
		 * 银行卡限额属性说明 参数名称 参数编码 是否必须 字段长度 描述和样例 
		 * 基本参数 交易结果代码 ret_code 是 String(4) 0000
		 * 交易结果描述 ret_msg 是 String(100) 交易成功 业务参数 
		 * 支持银行列表 support_banklist 否 String
		 * 二级列表 support_banklist 
		 * 银行编码 bank_code 否 String 
		 * 银行名称 bank_name 否 String 
		 * 卡类型 card_type 否 String 2-借记卡 3-信用卡 
		 * 单笔限额 single_amt 否 String 单位 元 整数数字 最大限额90000000，需商户前端自行处理 
		 * 单日限额 day_amt 否 String 单位 元 整数数字最大限额90000000，需商户前端自行处理 
		 * 单月限额 month_amt 否 String 单位 元 整数数字最大限额90000000，需商户前端自行处理 
		 * 银行状态 bank_status 否 String 0：正常 2：维护中
		 **/
		
		for (int i = 0; i < bankList.size(); i++) {
			JSONObject bank = bankList.getJSONObject(i);
			// 判断是否借记卡
			if (!bank.getString("card_type").equals("2")) {
				continue;
			}
			
			PayGateBank payGateBank = this.findPayGateBankByCode(
					Constants.PAYGATE_CODE_LLPAY, bank.getString("bank_code"));
			if (payGateBank == null) {
				return;
			}
			
			// 银行状态
			String bankStatus = bank.getString("bank_status");
			if (bankStatus.equals("0")) {
				payGateBank.setInuse(true);
			} else if (bankStatus.equals("2")) {
				payGateBank.setInuse(false);
			}
			
			// 银行限额
			payGateBank.setSingleLimit(bank.getLong("single_amt"));
			payGateBank.setDayLimit(bank.getLong("day_amt"));
			payGateBank.setMonthLimit(bank.getLong("month_amt"));
			
			payGateBank.setModifyDate(new Date());
			
			this.payGateBankMapper.updateByPrimaryKey(payGateBank);
		}
	}

	/**
	 * 查询支付网关银行
	 * @param payGateCode 支付网关编码
	 * @param payBankCode	银行编码
	 * @return
	 */
	private PayGateBank findPayGateBankByCode(String payGateCode, String payBankCode) {
		return this.payGateBankMapper.selectPayGateBankByCode(payGateCode, payBankCode);
	}

	@Override
	public void unbindYeePay(PayAPIService payAPIService, BankCard bankCard) throws Exception {
		String json = payAPIService.bindList(bankCard.getUser().getExternal(), YeepayApiConfig.IDENTITY_TYPE_USER_ID);
		JSONObject jsonObject = JSONObject.parseObject(json);
		if (jsonObject.containsKey("error_code")) {
			throw new RuntimeException("获取绑卡列表失败：" + jsonObject.toJSONString());
		}
		
		String bindid = "";
		UserBindCard userBindCard = JSONObject.parseObject(json, UserBindCard.class);
		for (BindCard card : userBindCard.getCardlist()) {
			// 卡号前6位和卡号后4位一致时，认为是匹配的卡
			if (bankCard.getCardNumber().startsWith(card.getCard_top())
			&& bankCard.getCardNumber().endsWith(card.getCard_last())) {
				bindid = card.getBindid();
			}
		}
		
		if (StringUtils.isEmpty(bindid)) {
			return;
		}
		
		String unbindJson = payAPIService.unbindCard(
				bindid, bankCard.getUser().getExternal(), YeepayApiConfig.IDENTITY_TYPE_USER_ID);
		if (JSONObject.parseObject(unbindJson).containsKey("error_code")) {
			throw new RuntimeException("解绑易宝支付失败：" + unbindJson);
		}
	}

	@Override
	public void addPayOrder(PayOrder payOrder) {
		payOrder.setCreateDate(new Date());
		payOrder.setModifyDate(new Date());
		if (this.payOrderMapper.insert(payOrder) < 1){
			throw new RuntimeException("插入支付订单失败");
		}
	}

	@Override
	public void advancePaymentFinancing(Long financingId, Date advancePaymentDate) {
		
		Financing financing = this.financingMapper.selectByPrimaryKey(financingId);
		
		LocalDate now = new LocalDate();
		LocalDate valueDate = new LocalDate(financing.getValueDate());
		LocalDate advancePaymentLocalDate = new LocalDate(advancePaymentDate);
		LocalDate settlementLocalDate = valueDate.plusDays(financing.getProduct().getTerm());
		
		if (!advancePaymentLocalDate.isAfter(valueDate)) {
			throw new RuntimeException("提前兑付时间不能早于起息日");
		}
		
		if (advancePaymentLocalDate.isBefore(now)) {
			throw new RuntimeException("提前兑付时间不能早于当前时间");
		}
		
		if (advancePaymentLocalDate.isAfter(settlementLocalDate)) {
			throw new RuntimeException("提前兑付时间不能晚于于最后兑付时间");
		}
		
		if (financing.getRepaymentTime() != null) {
			throw new RuntimeException("资产已兑付");
		}
		
		Period period = new Period(valueDate, advancePaymentLocalDate, PeriodType.days());
		financing.setTerm(period.getDays());
		financing.setSettlementDate(advancePaymentLocalDate.toDate());
		financing.setModifyDate(new Date());
		this.financingMapper.updateByPrimaryKey(financing);
	}

	@Override
	public List<PayGateBank> findPayGateBanksByPayGateCode(String payGateCode) {
		return this.payGateBankMapper.findPayGateBanksByPayGateCode(payGateCode);
	}

	@Override
	public PayGateBank findPayGateBank(Long payGateId, String bankCode) {
		PayGateBankExample example = new PayGateBankExample();
		example.appendCriterion("paygateid =", payGateId);
		example.appendCriterion("bankcode =", bankCode);
		return payGateBankMapper.selectOneByExample(example);
	}

	@Override
	public void sendPayIdentifyingCode(String mobile, Order order) {
		
		StringBuilder sb = new StringBuilder();
		Random random = new Random();
		for (int i = 0; i < 6; i++) {
			sb.append(String.valueOf(random.nextInt(10)));
		}

		String identifyingcode = sb.toString();
		logger.info("手机号【"+mobile+"】验证码：" + identifyingcode);
		
		String key = "PAY_IDENTIFYING_CODE" + mobile + order.getPayNumber();
		redisTemplate.opsForValue().set(key, identifyingcode);
		redisTemplate.expire(key, 600, SECONDS);

		final SMS sms = new SMS();
		sms.setMobile(mobile);
		sms.setMessage(String.format("支付验证码：%s,您于%s在快聚财支付%s元购买%s（请勿泄露）", 
				identifyingcode,
				DateFormatUtils.format(order.getCreateDate(), "MM月dd日 HH:mm"),
				order.getAmount().toString(),
				order.getProduct().getName()));
		sms.setChannel("alauda_verification");
		executor.execute(new Runnable() {
			@Override
			public void run() {
				smsService.sendSMS(sms);
			}
		});
	}

	@Override
	public void updateBankCardMobile(Long bankCardId, String mobile) {
		
		BankCard bankCard = bankCardMapper.selectByPrimaryKey(bankCardId);
		
		if (BankCard.Status.BINDED != bankCard.getStatus()) {
			return;
		}
		if (mobile.equals(bankCard.getMobile())) {
			return;
		}
		
		bankCard.setMobile(mobile);
		bankCardMapper.updateByPrimaryKey(bankCard);
	}

	@Override
	public void updateOrderPayGateStatusByPayNumber(String payNumber, String payGateStatus, String payGateStatusDescription) {
		orderMapper.updateOrderPayGateStatusByPayNumber(payNumber, payGateStatus, payGateStatusDescription);
	}

	/**
	 * 验证银卡信息
	 * @param model
	 * @param payNumber 支付订单号
	 * @param mobile 手机
	 * @param bankcard	银行卡
	 * @return
	 * @throws Exception 
	 */
	public String checkBankCard( 
			String payNumber, 
			String mobile, 
			BankCard bankcard) throws Exception {
		
		JytPayClient client = new JytPayClient(jytPayConfig);
		
		String bank_card_no = bankcard.getCardNumber(); // 银行卡号
		String id_num = bankcard.getCertId(); // 身份证号
		String id_name = bankcard.getUserName(); // 姓名
		String terminal_type = "02"; // 请求终端类型:01 APP，02 WAP，03 WEB，04 SIM卡，05 VI-POS，06 SD卡
		String bank_card_type = "D"; // 银行卡类型:D 借记卡 C 贷记卡 A 全部（如果商户平台借记卡贷记卡都支持的话传A）
		String phone_no = mobile; // 银行卡开户预留的手机号码
		
		StringBuffer xml = new StringBuffer();
		xml.append(client.getMsgHeadXml("TR4003", jytPayConfig.getMerchantId(), RandomStringUtils.randomNumeric(18)))
		   .append("<body>")
		   .append("<bank_card_no>").append(bank_card_no).append("</bank_card_no>")
		   .append("<id_num>").append(id_num).append("</id_num>")
		   .append("<id_name>").append(id_name).append("</id_name>")
		   .append("<terminal_type>").append(terminal_type).append("</terminal_type>")
		   .append("<bank_card_type>").append(bank_card_type).append("</bank_card_type>")
		   .append("<phone_no>").append(phone_no).append("</phone_no>")
		   .append("</body></message>");
		
		savePayNotifyLog(Constants.PAYGATE_CODE_JYTPAY, "TR4003Send", xml.toString());
		
		String sign = client.signMsg(xml.toString());
		String respXml = client.sendMsg(
				jytPayConfig.getAuthenticationServerUrl(), 
				jytPayConfig.getMerchantId(), 
				xml.toString(), 
				sign);
		
		savePayNotifyLog(Constants.PAYGATE_CODE_JYTPAY, "TR4003Response", respXml);
		
		String respCode = client.getMsgRespCode(respXml);
		String respDesc = client.getXmlText(respXml, "/message/head/resp_desc");
		
		if ("S0000000".equals(respCode)) {
			return null;
		}else {
			savePayNotifyLog(Constants.PAYGATE_CODE_JYTPAY, "TR4003Fail", respXml);
			if(payNumber != null)
				updateOrderPayGateStatusByPayNumber(payNumber, respCode, respDesc);
			return respDesc;
		}
	}

	
	/**
	 * 根据CardNumber获取银行代号
	 * @param cardNumber
	 * @return
	 */
	public String[] getBankCodeByCardNumber(String cardNumber){
		if(BANK_BIN_MAP == null){
			synchronized(this){
				BANK_BIN_MAP = new HashMap<String, String[]>();
				Parameter parameter = configureService.getParameter(Parameter.Category.Custom, "BANK_BIN_INFO");	
				if(parameter!=null){
					JSONArray array = (JSONArray) JSONArray.parse(parameter.getValue());
					for(int i=0;i<array.size();i++){
						JSONObject item = array.getJSONObject(i);
						BANK_BIN_MAP.put(item.getString("bankbin"), new String[]{item.getString("bankcode"),item.getString("bankname")});
					}
				}
			}
		}
		String cardbin = cardNumber.substring(0,6);
		logger.info(cardNumber);
		return BANK_BIN_MAP.get(cardbin);
	}
	
	
	
	
}
